package de.hbrs.selectionengine.optimization;

import java.util.logging.Level;
import java.util.logging.Logger;

import net.sf.javailp.Linear;
import net.sf.javailp.OptType;
import net.sf.javailp.Problem;
import net.sf.javailp.Result;
import net.sf.javailp.Solver;
import net.sf.javailp.SolverFactory;
import net.sf.javailp.SolverFactoryLpSolve;

import de.hbrs.selectionengine.model.Constraint;
import de.hbrs.selectionengine.model.ServiceClass;
import de.hbrs.selectionengine.model.WebService;
import de.hbrs.selectionengine.optimization.mmkp.NoFeasibleSolutionFoundException;
import de.hbrs.selectionengine.tool.Enum.AggregationType;

/**
 * This Class finds the best web service candidate in a serviceClass and returns
 * the best found service.
 * 
 * @author Sebastian
 * 
 */
public class LocalOptimitzation {

	private static final Logger logger = Logger.getLogger("Logging");

	public static WebService solve(ServiceClass sc, Constraint c) throws NoFeasibleSolutionFoundException {

		logger.log(Level.INFO, "local optimization starts.");
//		new UtilityCalculator2().calcUtilityForServcieClass(sc, c);

		SolverFactory factory = new SolverFactoryLpSolve();
		factory.setParameter(Solver.VERBOSE, 0);
		factory.setParameter(Solver.TIMEOUT, 100);

		Problem problem = new Problem();

		Linear linear = new Linear();

		// Define objectiv
		for (int i = 0; i < sc.getWebServices().size(); i++) {

				linear.add(sc.getWebServices().get(i).getUtility(), sc.getWebServices().get(i)
						.getId());
		}

		problem.setObjective(linear, OptType.MAX);

		linear = new Linear();

		// Define selection constraint
		for (int i = 0; i < sc.getWebServices().size(); i++) {

			linear.add(1, sc.getWebServices().get(i).getId());
		}

		problem.add(linear, "=", 1);

		for (int i = 0; i < c.getConstraintList().size(); i++) {

			linear = new Linear();

			for (int j = 0; j < sc.getWebServices().size(); j++) {

				// 0 = addition | 1 = product
				if (c.getConstraintList().get(i).getAggregationType().equals(AggregationType.MULTIPLICATION.name())) {

					linear.add(
							Math.log(sc.getWebServices().get(j).getQuality()
									.get(i).getValue()), sc.getWebServices()
									.get(j).getId());
				} else if(c.getConstraintList().get(i).getAggregationType().equals(AggregationType.ADDITION.name())) {
					linear.add(sc.getWebServices().get(j).getQuality()
							.get(i).getValue(), sc.getWebServices().get(j)
							.getId());
				}
			}

			// Kosten bekannt machen.
			// Maximalkosten angeben <= 33
			if (c.getConstraintList().get(i).getAnalyseStragey()) {
				// 0 = addition | 1 = product
				if (c.getConstraintList().get(i).getAggregationType().equals(AggregationType.MULTIPLICATION.name())) {

				problem.add(linear, ">=", Math.log(c.getConstraintList().get(i)
						.getValue()));
				}
				else if (c.getConstraintList().get(i).getAggregationType().equals(AggregationType.ADDITION.name())) {
					problem.add(linear, ">=", c.getConstraintList().get(i)
							.getValue());
				}
									
			} else {
				
				if (c.getConstraintList().get(i).getAggregationType().equals(AggregationType.MULTIPLICATION.name())) {

					problem.add(linear, "<=", Math.log(c.getConstraintList().get(i)
							.getValue()));
					}
					else if (c.getConstraintList().get(i).getAggregationType().equals(AggregationType.ADDITION.name())) {
						problem.add(linear, "<=", c.getConstraintList().get(i)
								.getValue());
					}
			}
		}

		// For each service
		for (int i = 0; i < sc.getWebServices().size(); i++) {
			problem.setVarType(sc.getWebServices().get(i).getId(),
					Integer.class);
		}

		Solver solver = factory.get(); // you should use this solver only
		// once
		// for one problem
//		System.out.println("Problem= " + problem);
//		logger.log(Level.INFO, "PROBLEM: " + problem);
		Result result = solver.solve(problem);

		if (result == null) {
			throw new NoFeasibleSolutionFoundException();

		} else {
//			logger.log(Level.INFO, result.toString());
		}

		for (int i = 0; i < sc.getWebServices().size(); i++) {

			WebService ws = sc.getWebServices().get(i);

			if (result.getBoolean(ws.getId())) {
				return ws;
			}
		}
		return null;
	}
}
